grammar MiniJavaGrammar;

options {
	output=AST;
}

tokens {
	STATLIST;
}

@members {
}

program	:	(packages)* (imports)* mainClass (classDecl)* EOF
	;
packages:	'package' identifier+ ';' (NEWLINE)*
	;
imports	:	'import' identifier+ '*'? ';' (NEWLINE)*
	;
mainClass
	:	'public' 'class' identifier ('extends' identifier)? LB 'public' 'static' 'void' 'main' LP 'String' (LSB RSB | '...') identifier RP LB methodStatements RB RB
	;
classDecl
	:	(packages)* (imports)* ('public')? 'class' identifier ('extends' identifier)? LB classStatements RB
	;
fieldDecl
	:	('public')? attrDecl
	;
attrDecl:	type identifier (ASSIGN assignExpr)? (',' identifier (ASSIGN assignExpr)? )* ';'
	;
assignExpr
	:	identifier
	|	INT
	|	'true'
	|	'false'
	|	'this'
	|	('new')? methodCall ('.' ID (LP (argumentsList)? RP)? )*
	;
classStatements
	:	(classStatement | NEWLINE)*
	;
classStatement
	:	fieldDecl
	|	methodDecl
	|	constructor
	;
constructor
	:	('public')? identifier LP (paramsList)? RP LB methodStatements RB
	;
methodDecl
	:	('public')? type identifier LP (paramsList)? RP LB methodStatements RB
	;
methodStatements
	:	(methodStatement | NEWLINE)*
	;
methodStatement
	:	attrDecl
	|	identifier ASSIGN assignExpr ';'
	|	('new')? methodCall ('.' ID (LP (argumentsList)? RP)? )* ';'
	|	ifStatement
	|	whileStatement
	|	printStatement
	|	tryStatement
	;
methodCall
	:	identifier LP (argumentsList)? RP
	;
paramsList
	:	type (identifier)? (',' type (identifier)? )*
	;
argumentsList
	:	identifier (',' identifier)*
	;
expression
	:	assignExpr
	|	assignExpr LSB assignExpr RSB
	|	assignExpr ('&&' | '||' | '<' | '<=' | '>' | '>=' | '+' | '-' | '*') assignExpr
	|	assignExpr '.length'
	|	'!' expression
	|	LP expression RP
	;
ifStatement
	:	'if' LP expression RP LB methodStatements RB ('else' LB methodStatements RB)?
	;
whileStatement
	:	'while' LP expression RP LB methodStatements RB
	;
printStatement
	:	'System.out.println' LP (INT (',' INT)*)? RP ';'
	;
tryStatement
	:	'try' LB methodStatements RB 'catch' LP (type (identifier)? )? RP LB methodStatements RB
	;
type	:	'int'
	|	'boolean'
	|	'int' LSB RSB
	|	identifier
	;
identifier
	:	ID ('.' ID)* // With namespace, like System.in
	;


ASSIGN	:	'=';
EOF	:	;
ID	:	('a'..'z' | 'A'..'Z') ('_' | 'a'..'z' | 'A'..'Z' | '0'..'9')*;
INT	:	'0' | ('-')? ('1'..'9') ('0'..'9')*;
NEWLINE	:	'\r'? '\n';
SPACING	:	'\t'*;

LP	:	'(';
RP	:	')';
LSB	:	'[';
RSB	:	']';
LB	:	'{';
RB	:	'}';